module Aio
	private
	
	# Arduino sketch written in C.
	
	SKETCH = <<-SKETCH_END
		#define ISIZE 3
		#define OSIZE 4
		
		void setup() {
		  Serial.begin(#{BAUDRATE}L);
		  Serial.setTimeout(#{TIMEOUT}L);
		}
		
		byte input[ISIZE];
		byte output[OSIZE];
		
		void loop() {
		  byte lrc;
		  int param16;
		  long param32;
		  
		  while(Serial.read() != #{SYNCBYTE}); /* wait for sync byte */
		  
		  if (readBytes(input, ISIZE) && readBytes(&lrc, 1) && (lrc == getLRC(input, ISIZE))) {
		    Serial.write(#{ACK});
		    switch(input[0]) {
		      case 1: /* pinMode */
		        pinMode(input[1], input[2]);
		        break;
		      case 2: /* digitalRead */
		        output[0] = digitalRead(input[1]);
		        fill(output, OSIZE, 1);
		        Serial.write(output, OSIZE);
		        Serial.write(getLRC(output, OSIZE));
		        break;
		      case 3: /* digitalWrite */
		        digitalWrite(input[1], input[2]);
		        break;
		      case 4: /* analogRead */
		        *((int *)output) = analogRead(input[1]);
		        fill(output, OSIZE, 2);
		        Serial.write(output, OSIZE);
		        Serial.write(getLRC(output, OSIZE));
		        break;
		      case 5: /* analogWrite */
		        analogWrite(input[1], input[2]);
		        break;
		      case 6: /* analogReference */
		        analogReference(input[1]);
		        break;
		      case 7: /* millis */
		        *((long *)output) = millis();
		        Serial.write(output, OSIZE);
		        Serial.write(getLRC(output, OSIZE));
		        break;
		      case 8: /* ready */
		        /* nop */
		        break;
		    }
		  } else {
		    Serial.write(#{NAK});
		  }
		}
		
		byte getLRC(byte *buff, int length) {
		  byte lrc = 0;
		  
		  for(int c = 0; c < length; c++)
		    lrc += buff[c];
		  return ((lrc ^ 0xff) + 1);
		}
		
		int readBytes(byte *buff, int length) {
		  return (Serial.readBytes(buff, length) == length);
		}
		
		void fill(byte *buff, int length, int start) {
		  for(int c = start; c < length; c++)
		    buff[c] = random(256);
		}
	SKETCH_END
end
